package com.twotwoshop.service.goods.service.Impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.twotwoshop.commom.goods.SortTypeConstants;
import com.twotwoshop.commom.rabbitmq.RabbitConstants;
import com.twotwoshop.commom.redis.RedisConstants;
import com.twotwoshop.domin.category.pojos.ProductCategory;
import com.twotwoshop.domin.common.dtos.PageResponseResult;
import com.twotwoshop.domin.common.dtos.ResponseResult;
import com.twotwoshop.domin.common.enums.AppHttpCodeEnum;
import com.twotwoshop.domin.goods.dtos.GoodsSearchDto;
import com.twotwoshop.domin.goods.dtos.ProductDto;
import com.twotwoshop.domin.goods.pojo.Product;
import com.twotwoshop.domin.goods.vos.ProductDetailsVo;
import com.twotwoshop.domin.goods.vos.ProductVo;
import com.twotwoshop.domin.user.pojos.ApUser;
import com.twotwoshop.fegin.api.user.IUserClient;
import com.twotwoshop.service.goods.mapper.ProductCategoryMapper;
import com.twotwoshop.service.goods.mapper.ProductMapper;
import com.twotwoshop.service.goods.service.ProductService;
import com.twotwoshop.util.thread.AppThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.concurrent.ListenableFutureCallback;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.twotwoshop.commom.goods.ProductConstants.STATUS_DOWN;
import static com.twotwoshop.commom.goods.ProductConstants.STATUS_UP;

@Service
@RequiredArgsConstructor
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper,Product> implements ProductService{
    
    private final ProductMapper productMapper;

    private final ProductCategoryMapper productCategoryMapper;

    private final RabbitTemplate rabbitTemplate;

    private final IUserClient userClient;

    private final StringRedisTemplate stringRedisTemplate;

    private final RedissonClient redissonClient;

    /**
     * 发布商品
     * @param productDto
     * @return
     */
    @Override
    @Transactional
    public ResponseResult publishProduct(ProductDto productDto) {


        //添加分布式锁防止重复提交

        // 创建锁对象
        RLock redisLock = redissonClient.getLock(RedisConstants.GOODS_PUBLISH_LOCK_KEY + productDto.getUserId()+productDto.getId());
        // 尝试获取锁
        boolean isLock = redisLock.tryLock();
        // 判断
        if (!isLock) {
            // 获取锁失败，直接返回失败或者重试
            return ResponseResult.errorResult(AppHttpCodeEnum.TOKEN_INVALID,"不允许重复发布");
        }


        try {
            //1.检查参数
            if (productDto == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
            }

            // 建议添加以下校验：
            if (StringUtils.isBlank(productDto.getTitle())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品标题不能为空");
            }

            // 将 0 转换为 BigDecimal
            BigDecimal zero = BigDecimal.ZERO;

            if (productDto.getPrice() == null || productDto.getPrice().compareTo(zero) <= 0) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品价格不合法");
            }
            if (productDto.getCategoryId() == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品类别不能为空");
            }


            // 1. 图片数量限制
            if(productDto.getImages().size() > 9) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品图片不能超过9张");
            }


            // 实现发布商品的逻辑
            Product product = new Product();
            BeanUtils.copyProperties(productDto, product);

            //封面图片  list---> string  将图片的List转化为String存入数据库
            if(productDto.getImages() != null && productDto.getImages().size() > 0){
                //[1dddfsd.jpg,sdlfjldk.jpg]-->   1dddfsd.jpg,sdlfjldk.jpg
                String imageStr = StringUtils.join(productDto.getImages(), ",");
                product.setImages(imageStr);
            }

            Integer userId = AppThreadLocalUtil.getUser().getId();


            product.setStatus(STATUS_UP);
            product.setUserId(Long.valueOf(userId));


            product.setCreatedTime(LocalDateTime.now());
            product.setUpdatedTime(LocalDateTime.now());


            //插入数据库
            int insert = productMapper.insert(product);
            if (insert != 1) {
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
            }


            //异步插入es
            // 4. 构建要索引的 Elasticsearch 和 Redis文档
            Map<String, Object> esDocument = BeanUtil.beanToMap(product, new HashMap<>(), CopyOptions.create()
                    //忽略空的值
                    .setIgnoreNullValue(true)
                    //将hash的value类型转换为String
                    .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? null : fieldValue.toString()));

            //4.1 设置这个map为add 让mq识别他为添加新商品操作
            esDocument.put(RabbitConstants.ACTION, RabbitConstants.ACTION_ADD);


            //使用DateTimeFormatter处理LocalDateTime
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            if (product.getCreatedTime() != null) {
                String createdTime = product.getCreatedTime().format(formatter);
                esDocument.put("createdTime", createdTime);
            }
            if (product.getUpdatedTime() != null) {
                String updatedTime = product.getUpdatedTime().format(formatter);
                esDocument.put("updatedTime", updatedTime);
            }


            //生产者确认
            // 1. 创建CorrelationData
            CorrelationData cd = new CorrelationData();
            // 2. 给Future添加ConfirmCallback
            cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {

                @Override
                public void onFailure(Throwable ex) {
                    // 2.1.Future发生异常时的处理逻辑，基本不会触发
                    log.error("handle message ack fail", ex);
                }

                @Override
                public void onSuccess(CorrelationData.Confirm result) {
                    // 2.2.Future接收到回执的处理逻辑，参数中的result就是回执内容
                    if(result.isAck()){// result.isAck() boolean类型, true代表ack回执, false 代表 nack回执
                        log.debug("发送消息成功，收到 ack!");
                    }else{// result.getReason(), String类型, 返回nack时的异常描述
                        log.error("发送消息失败，收到 nack，reason : {}");
                    }
                }
            });

            // 5. 优化添加商品信息 数据库添加完后异步发送消息更新es与Redis
            rabbitTemplate.convertAndSend(RabbitConstants.TWOTWO_GOODS_TOPIC, esDocument,cd);


            return ResponseResult.okResult(product);
        } catch (BeansException e) {
            throw new RuntimeException(e);
        } catch (AmqpException e) {
            throw new RuntimeException(e);
        } finally {

            //判断是当前线程持有锁 才能释放锁
            if (redisLock.isHeldByCurrentThread()) {
                redisLock.unlock();
            }

        }
    }


    /**
     * 查看我的发布
     * @param goodsSearchDto
     * @return
     */
    @Override
    public ResponseResult listProducts(GoodsSearchDto goodsSearchDto) {
        // 1.检查参数
        goodsSearchDto.checkParam();


        //创建返回值
        ResponseResult responseResult = new ResponseResult();

        // 2.创建分页对象
        IPage<Product> page = new Page<>(goodsSearchDto.getPage(), goodsSearchDto.getSize());

        // 3.构建查询条件
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();

        // 获取当前登录用户ID
        Long userId = AppThreadLocalUtil.getUser().getId().longValue();

        // 查询条件：用户ID
        queryWrapper.eq(Product::getUserId, userId);



        // 关键字搜索（标题或描述）
        if (StringUtils.isNotBlank(goodsSearchDto.getKeyword())) {
            queryWrapper.and(wrapper -> wrapper
                    .like(Product::getTitle, goodsSearchDto.getKeyword())
                    .or()
                    .like(Product::getDescription, goodsSearchDto.getKeyword())
            );
        }


        // 按创建时间倒序排序
        queryWrapper.orderByDesc(Product::getCreatedTime);

        // 4.执行查询
        page = productMapper.selectPage(page, queryWrapper);

        // 5.转换为VO对象
        IPage<ProductVo> voPage = page.convert(product -> {
            ProductVo vo = new ProductVo();
            BeanUtils.copyProperties(product, vo);

            //将图片路径转化为集合
            List<String> imageList = Arrays.stream(product.getImages().split(","))
                    .map(String::trim)
                    .collect(Collectors.toList());

            vo.setImages(imageList);


            return vo;
        });



        //3.结果返回
        responseResult = new PageResponseResult(goodsSearchDto.getPage(), goodsSearchDto.getSize(), (int) page.getTotal());
        responseResult.setData(voPage.getRecords());


        return responseResult;
    }

    /**
     * 获取全部商品
     *
     * @param goodsSearchDto
     * @return
     */
    @Override
    public ResponseResult listProductsAll(GoodsSearchDto goodsSearchDto) {

        // 1.检查参数
        goodsSearchDto.checkParam();


        //创建返回值
        ResponseResult responseResult = new ResponseResult();

        // 2.创建分页对象
        IPage<Product> page = new Page<>(goodsSearchDto.getPage(), goodsSearchDto.getSize());

        // 3.构建查询条件
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();

        //获取上架的商品
        queryWrapper.eq(Product::getStatus, STATUS_UP);

        //后发布的先获取
        //默认排序
        if (goodsSearchDto.getSortType().equals(SortTypeConstants.DEFAULT)){
            queryWrapper.orderByDesc(Product::getCreatedTime);
        }

        //创建时间排序
        if (goodsSearchDto.getSortType().equals( SortTypeConstants.TIME)){
            queryWrapper.orderByAsc(Product::getCreatedTime);
        }

        //热度排序
        if (goodsSearchDto.getSortType().equals(SortTypeConstants.VIEWS)){
            queryWrapper.orderByDesc(Product::getViews);
        }

        //类别排序
        if (goodsSearchDto.getCategoryId()!=null){
            queryWrapper.eq(Product::getCategoryId, goodsSearchDto.getCategoryId());
        }


        //查询商品信息
        page = productMapper.selectPage(page, queryWrapper);



        // 5.转换为VO对象
        IPage<ProductVo> voPage = page.convert(product -> {
            ProductVo vo = new ProductVo();
            BeanUtils.copyProperties(product, vo);

            //将图片路径转化为集合
            List<String> imageList = Arrays.stream(product.getImages().split(","))
                    .map(String::trim)
                    .collect(Collectors.toList());

            vo.setImages(imageList);

            //查询发布商品人的昵称和头像
            ResponseResult userInfo = userClient.getUserInfoById(product.getUserId());
            if (userInfo.getCode()==200){
                //拿取用户信息
                String jsonString = JSONUtil.toJsonStr(userInfo.getData());
                ApUser user = JSONUtil.toBean(jsonString, ApUser.class);

                //设置用户的名称和头像
                vo.setName(user.getName());
                vo.setImage(user.getImage());
                vo.setUserId(user.getId().longValue());
            }


            return vo;
        });


        //3.结果返回
        responseResult = new PageResponseResult(goodsSearchDto.getPage(), goodsSearchDto.getSize(), (int) page.getTotal());
        responseResult.setData(voPage.getRecords());


        return responseResult;
    }

    /**
     * 获取商品详情信息
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult productDetail(Long id) {

        //1.检查参数
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }


        //1.先去Redis查询 如果redis没有 再去数据库查
        //1.redis查询商品详情信息
        Map<Object, Object> GoodsMap = stringRedisTemplate.opsForHash().entries(RedisConstants.GOODS_DETAIILS_KEY + id);

        //判断是否命中
        //2.1 命中 返回Redis中的信息
        if (GoodsMap.size()!=0) {




            //异步更新商品浏览量  ###
            upViews(id);




            // 获取浏览次数
            int views = stringRedisTemplate.opsForZSet().score(RedisConstants.GOODS_VIEWS_KEY, id.toString()).intValue();
            if (views>=0) {
                GoodsMap.put("views", views);
            }




            ProductDetailsVo goods = BeanUtil.fillBeanWithMap(GoodsMap, new ProductDetailsVo(), true);
            return ResponseResult.okResult(goods);
        }


        //2.2  未命中根据id查询商品详情信息
        //查询商品详情信息
        Product product = productMapper.selectById(id);
        if (product == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
        }



        //组装信息
        ProductDetailsVo productDetailsVo = new ProductDetailsVo();
        BeanUtils.copyProperties(product, productDetailsVo);

        //查询商品类别信息
        ProductCategory productCategory = productCategoryMapper.selectById(product.getCategoryId());

        //组装类别
        if (productCategory != null) {
            productDetailsVo.setCategoryName(productCategory.getName());
        }

        //将图片路径转化为集合
        List<String> imageList = Arrays.stream(product.getImages().split(","))
                .map(String::trim)
                .collect(Collectors.toList());

        //传入图片集合
        productDetailsVo.setImages(imageList);

        //组装用户信息
        //查询发布商品人的昵称和头像
        ResponseResult userInfo = userClient.getUserInfoById(product.getUserId());
        if (userInfo.getCode()==200){
            //拿取用户信息
            String jsonString = JSONUtil.toJsonStr(userInfo.getData());
            ApUser user = JSONUtil.toBean(jsonString, ApUser.class);

            //设置用户的名称和头像
            productDetailsVo.setName(user.getName());
            productDetailsVo.setImage(user.getImage());
            productDetailsVo.setUserId(user.getId().longValue());
        }


        // 4. 构建要索引的 Elasticsearch 和 Redis文档
        Map<String, Object> esDocument = BeanUtil.beanToMap(productDetailsVo, new HashMap<>(), CopyOptions.create()
                //忽略空的值
                .setIgnoreNullValue(true)
                //将hash的value类型转换为String
                .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? null : fieldValue.toString()));

        //3.将数据缓存到Redis中
        stringRedisTemplate.opsForHash().putAll(RedisConstants.GOODS_DETAIILS_KEY+id, esDocument);





        return ResponseResult.okResult(productDetailsVo);
    }


    /**
     * 上下架商品
     * @param productDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateStatus(ProductDto productDto) {

        // 1.参数校验
        if (productDto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品ID不能为空");
        }
        if (productDto.getStatus() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品状态不能为空");
        }

        // 2.查询商品是否存在
        Product product = productMapper.selectById(productDto.getId());
        if (product == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "商品不存在");
        }

        Long userId;
        // 3.验证是否是当前用户的商品
        if (productDto.getUserId()==null){
            userId = AppThreadLocalUtil.getUser().getId().longValue();
        }else {
            userId = productDto.getUserId();
        }


        if (!product.getUserId().equals(userId)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH, "无权操作此商品");
        }

        // 4.验证状态值是否合法（假设1是上架，0是下架）
        if (productDto.getStatus() != STATUS_DOWN && productDto.getStatus() != STATUS_UP) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品状态值不正确");
        }

        // 5.更新商品状态
        Product updateProduct = new Product();
        updateProduct.setId(productDto.getId());
        updateProduct.setStatus(productDto.getStatus());
        updateProduct.setUpdatedTime(LocalDateTime.now());




        int rows = productMapper.updateById(updateProduct);

        if (rows > 0) {

            Product esProduct = productMapper.selectById(productDto.getId());
            //更新成功后发送通知 更改es
            //异步插入es
            // 4. 构建要索引的 Elasticsearch 和 Redis文档
            Map<String, Object> esDocument = BeanUtil.beanToMap(esProduct, new HashMap<>(), CopyOptions.create()
                    //忽略空的值
                    .setIgnoreNullValue(true)
                    //将hash的value类型转换为String
                    .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? null : fieldValue.toString()));

            //4.1 设置这个map为add 让mq识别他为更改新商品操作
            esDocument.put(RabbitConstants.ACTION, RabbitConstants.ACTION_UPDATE);


            //使用DateTimeFormatter处理LocalDateTime
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            if (product.getCreatedTime() != null) {
                String createdTime = product.getCreatedTime().format(formatter);
                esDocument.put("createdTime", createdTime);
            }
            if (product.getUpdatedTime() != null) {
                String updatedTime = product.getUpdatedTime().format(formatter);
                esDocument.put("updatedTime", updatedTime);
            }



            //生产者确认
            // 1. 创建CorrelationData
            CorrelationData cd = new CorrelationData();
            // 2. 给Future添加ConfirmCallback
            cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {

                @Override
                public void onFailure(Throwable ex) {
                    // 2.1.Future发生异常时的处理逻辑，基本不会触发
                    log.error("handle message ack fail", ex);
                }

                @Override
                public void onSuccess(CorrelationData.Confirm result) {
                    // 2.2.Future接收到回执的处理逻辑，参数中的result就是回执内容
                    if(result.isAck()){// result.isAck() boolean类型, true代表ack回执, false 代表 nack回执
                        log.debug("发送消息成功，收到 ack!");
                    }else{// result.getReason(), String类型, 返回nack时的异常描述
                        log.error("发送消息失败，收到 nack，reason : {}");
                    }
                }
            });

            // 5. 优化添加商品信息 数据库添加完后异步发送消息更新es与Redis
            rabbitTemplate.convertAndSend(RabbitConstants.TWOTWO_GOODS_TOPIC, esDocument,cd);



            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);

        } else {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "更新失败");
        }

    }

    /**
     * 修改商品信息
     *
     * @param productDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateProduct(ProductDto productDto) {
        // 1.参数校验
        if (productDto == null || productDto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "参数错误");
        }

        // 2.查询原商品信息
        Product oldProduct = productMapper.selectById(productDto.getId());
        if (oldProduct == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "商品不存在");
        }

        // 3.验证是否是当前用户的商品

        Integer userId = AppThreadLocalUtil.getUser().getId();

        if (!oldProduct.getUserId().equals(Long.valueOf(userId))) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH, "无权修改此商品");
        }

        // 4.封装更新数据
        Product product = new Product();
        BeanUtils.copyProperties(productDto, product);

        // 5.处理图片列表
        if (productDto.getImages() != null && !productDto.getImages().isEmpty()) {
            String imageStr = StringUtils.join(productDto.getImages(), ",");
            product.setImages(imageStr);
        }

        // 6.设置更新时间
        product.setUpdatedTime(LocalDateTime.now());

        // 7.保持不可修改字段
        product.setUserId(oldProduct.getUserId());
        product.setCreatedTime(oldProduct.getCreatedTime());
        // 如果没有传入状态，保持原状态
        if (product.getStatus() == null) {
            product.setStatus(oldProduct.getStatus());
        }

        // 8.执行更新
        try {
            int rows = productMapper.updateById(product);
            if (rows > 0) {

                //更新成功后发送通知 更改es
                //异步插入es
                // 4. 构建要索引的 Elasticsearch 和 Redis文档
                Map<String, Object> esDocument = BeanUtil.beanToMap(product, new HashMap<>(), CopyOptions.create()
                        //忽略空的值
                        .setIgnoreNullValue(true)
                        //将hash的value类型转换为String
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? null : fieldValue.toString()));

                //4.1 设置这个map为add 让mq识别他为添加新商品操作
                esDocument.put(RabbitConstants.ACTION, RabbitConstants.ACTION_UPDATE);


                //使用DateTimeFormatter处理LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                if (product.getCreatedTime() != null) {
                    String createdTime = product.getCreatedTime().format(formatter);
                    esDocument.put("createdTime", createdTime);
                }
                if (product.getUpdatedTime() != null) {
                    String updatedTime = product.getUpdatedTime().format(formatter);
                    esDocument.put("updatedTime", updatedTime);
                }



                //生产者确认
                // 1. 创建CorrelationData
                CorrelationData cd = new CorrelationData();
                // 2. 给Future添加ConfirmCallback
                cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {

                    @Override
                    public void onFailure(Throwable ex) {
                        // 2.1.Future发生异常时的处理逻辑，基本不会触发
                        log.error("handle message ack fail", ex);
                    }

                    @Override
                    public void onSuccess(CorrelationData.Confirm result) {
                        // 2.2.Future接收到回执的处理逻辑，参数中的result就是回执内容
                        if(result.isAck()){// result.isAck() boolean类型, true代表ack回执, false 代表 nack回执
                            log.debug("发送消息成功，收到 ack!");
                        }else{// result.getReason(), String类型, 返回nack时的异常描述
                            log.error("发送消息失败，收到 nack，reason : {}");
                        }
                    }
                });

                // 5. 优化添加商品信息 数据库添加完后异步发送消息更新es与Redis
                rabbitTemplate.convertAndSend(RabbitConstants.TWOTWO_GOODS_TOPIC, esDocument,cd);


                // 查询更新后的完整信息
                Product updatedProduct = productMapper.selectById(product.getId());
                return ResponseResult.okResult(updatedProduct);
            } else {
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "更新失败");
            }
        } catch (Exception e) {
            log.error("更新商品信息失败", e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "系统错误");
        }
    }


    /**
     * 删除商品信息
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteProduct(Long id) {
        // 1.参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "商品ID不能为空");
        }

        // 2.查询商品是否存在
        Product product = productMapper.selectById(id);
        if (product == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "商品不存在");
        }

        // 3.验证是否是当前用户的商品
        Integer userId = AppThreadLocalUtil.getUser().getId();
        if (!product.getUserId().equals(Long.valueOf(userId))) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH, "无权删除此商品");
        }

        try {
            // 4.执行删除操作（这里可以选择物理删除或逻辑删除）

            // 方式一：物理删除
            int rows = productMapper.deleteById(id);


            if (rows > 0) {
                //更新成功后发送通知 更改es
                //异步插入es
                // 4. 构建要索引的 Elasticsearch 和 Redis文档
                Map<String, Object> esDocument = BeanUtil.beanToMap(product, new HashMap<>(), CopyOptions.create()
                        //忽略空的值
                        .setIgnoreNullValue(true)
                        //将hash的value类型转换为String
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? null : fieldValue.toString()));

                //4.1 设置这个map为add 让mq识别他为添加新商品操作
                esDocument.put(RabbitConstants.ACTION, RabbitConstants.ACTION_DELETE);


                //使用DateTimeFormatter处理LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                if (product.getCreatedTime() != null) {
                    String createdTime = product.getCreatedTime().format(formatter);
                    esDocument.put("createdTime", createdTime);
                }
                if (product.getUpdatedTime() != null) {
                    String updatedTime = product.getUpdatedTime().format(formatter);
                    esDocument.put("updatedTime", updatedTime);
                }



                //生产者确认
                // 1. 创建CorrelationData
                CorrelationData cd = new CorrelationData();
                // 2. 给Future添加ConfirmCallback
                cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {

                    @Override
                    public void onFailure(Throwable ex) {
                        // 2.1.Future发生异常时的处理逻辑，基本不会触发
                        log.error("handle message ack fail", ex);
                    }

                    @Override
                    public void onSuccess(CorrelationData.Confirm result) {
                        // 2.2.Future接收到回执的处理逻辑，参数中的result就是回执内容
                        if(result.isAck()){// result.isAck() boolean类型, true代表ack回执, false 代表 nack回执
                            log.debug("发送消息成功，收到 ack!");
                        }else{// result.getReason(), String类型, 返回nack时的异常描述
                            log.error("发送消息失败，收到 nack，reason : {}");
                        }
                    }
                });

                // 5. 优化添加商品信息 数据库添加完后异步发送消息更新es与Redis
                rabbitTemplate.convertAndSend(RabbitConstants.TWOTWO_GOODS_TOPIC, esDocument,cd);


                return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
            } else {
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "删除失败");
            }
        } catch (Exception e) {
            log.error("删除商品失败，商品ID：{}", id, e);
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "系统错误");
        }
    }


    /**
     * 异步更新商品的浏览量
     *
     * @param
     * @return
     */
    @Override
    @Async("twotwoExecutor")
    public void upViews(Long id) {

        log.info("线程池异步更新浏览次数成功");


        //redis异步更新商品浏览次数
        stringRedisTemplate.opsForZSet().incrementScore(
                RedisConstants.GOODS_VIEWS_KEY,
                id.toString(),
                1
        );

    }



    /**
     * 根据用户id获取发布商品
     *
     * @param userId
     * @return
     */
    @Override
    public ResponseResult listProductsByUserId(Long userId) {

        //1.参数判空
        if (userId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.构造查询条件 根据用户id查询其发布的商品
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<Product>();
        //查询发布的商品
        queryWrapper.eq(Product::getUserId, userId)
                .eq(Product::getStatus, STATUS_UP)
                .orderByDesc(Product::getCreatedTime);

        List<Product> products = productMapper.selectList(queryWrapper);

        if (products == null || products.isEmpty()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        String jsonStrList = JSONUtil.toJsonStr(products);

        return ResponseResult.okResult(jsonStrList);
    }


}